home *** CD-ROM | disk | FTP | other *** search
/ Acorn User: China / Acorn User China CD-ROM (UK) (Disc A) / Acorn User China CD-ROM (UK) (Disc A).bin / DEMON / MISC / NETLITE2.ARC / NET / c / NNTPCLI < prev    next >
Encoding:
Text File  |  1993-04-12  |  22.6 KB  |  609 lines

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <stdarg.h>
  4. #include <time.h>
  5. #include <ctype.h>
  6. #include <string.h>
  7. #include "global.h"
  8. #include "timer.h"
  9. #include "cmdparse.h"
  10. #include "netuser.h"
  11. #include "nntp.h"
  12. #include "smtp.h"
  13. #include "domain.h"
  14. #include "misc.h"
  15. #include "tcp.h"
  16. #include "mbuf.h"
  17. #include "reader.h"
  18. #include "flex.h"
  19. #include "os.h"
  20. #include "swis.h"
  21.  
  22. struct nntpservers *Nntpservers = NULLNNTP;
  23.  
  24. static void nntptick(void *);
  25. static void make_got_table(int, void *);
  26. static int doadds(int, char **);
  27. static int dodrops(int, char **);
  28. static int dokicks(int, char **);
  29. static int dostop(int, char **);
  30. static void quit(struct nntpservers *, BOOL);
  31. static void nntp_rec(struct tcb *, int16);
  32. static void nntp_cts(struct tcb *, int16);
  33. static void nntp_state(struct tcb *, char, char);
  34. static void sendit(struct nntpservers *, char *, ...);
  35.  
  36. extern int16 lport;                     /* local port placeholder */
  37.  
  38. static char quitcmd[] = "QUIT\r\n";
  39.  
  40. struct cmds nntpcmds[] = {
  41.   "addserver",    doadds,        4,   "nntp addserver <name> <time> <abbr>", NULLCHAR,
  42.   "dropserver",   dodrops,       2,   "nntp dropserver <name|abbr>",         NULLCHAR,
  43.   "kick",         dokicks,       2,   "nntp kick <name|abbr>",               NULLCHAR,
  44.   "stop",         dostop,        0,   "nntp stop <name|abbr>",               NULLCHAR,
  45.   NULLCHAR,
  46. };
  47.  
  48. int donntp(int argc, char **argv)
  49. {
  50.         return subcmd(nntpcmds,argc,argv);
  51. }
  52.  
  53. static int doadds(int argc, char *argv[])
  54. {
  55.         struct nntpservers *np;
  56.         int lh, ll, hh, hl;
  57.         int i;
  58.  
  59.         for(np = Nntpservers; np != NULLNNTP; np = np->next)
  60.                 if (stricmp(np->name, argv[1]) == 0) 
  61.                         break;
  62.  
  63.         if (np == NULLNNTP)
  64.         {
  65.                 np = (struct nntpservers *) calloc(1,sizeof(struct nntpservers));
  66.                 np->name    = strdup(argv[1]);
  67.                 np->abbr    = strdup(argv[3]);
  68.                 np->ipdest  = resolve(argv[1]);
  69.                 np->next    = Nntpservers;
  70.                 Nntpservers = np;
  71.                 np->lowtime = np->hightime = -1;
  72.                 np->nntpcli_t.func = nntptick;  /* what to call on timeout */
  73.                 np->nntpcli_t.arg = (void *)np;
  74.                 np->rfile = NULLFILE;
  75.                 np->sfile = NULLFILE;
  76.                 np->tfile = NULLFILE;
  77.                 np->got_table = NULL;
  78.         }
  79.  
  80.         if (argc > 4)
  81.         {
  82.                 for (i = 4; i < argc; ++i)
  83.                 {
  84.                         if (isdigit(*argv[i]))
  85.                         {
  86.                                 sscanf(argv[i], "%d:%d-%d:%d", &lh, &ll, &hh, &hl);
  87.                                 np->lowtime = lh * 100 + ll;
  88.                                 np->hightime = hh * 100 + hl;
  89.                         } 
  90.                 }
  91.         }
  92.  
  93.         /* set timer duration */
  94.         set_timer(&np->nntpcli_t, atol(argv[2]) * 1000L);
  95.         start_timer(&np->nntpcli_t);            /* and fire it up */
  96.  
  97.         make_got_table(0, (void *)np);
  98.  
  99.         return 0;
  100. }
  101.  
  102. static int dodrops(int argc, char *argv[])
  103. {
  104.         struct nntpservers *np, *npprev = NULLNNTP;
  105.  
  106.         argc = argc;
  107.  
  108.         for(np = Nntpservers; np != NULLNNTP; npprev = np, np = np->next)
  109.         {
  110.                 if (stricmp(np->name, argv[1]) == 0 ||
  111.                     stricmp(np->abbr, argv[1]) == 0)
  112.                 {
  113.                         stop_timer(&np->nntpcli_t);
  114.                         free(np->name);
  115.                         free(np->abbr);
  116.                         if (np->rfile != NULLFILE) fclose(np->rfile);
  117.                         if (np->sfile != NULLFILE) fclose(np->sfile);
  118.                         if (np->tfile != NULLFILE) fclose(np->tfile);
  119.                         if (np->got_table != NULL)
  120.                         {
  121.                                 flex_free((flex_ptr) &(np->got_table));
  122.                                 np->got_table = NULL;
  123.                                 np->msg_tot = 0;
  124.                         }
  125.                         if(npprev != NULLNNTP)
  126.                                 npprev->next = np->next;
  127.                         else
  128.                                 Nntpservers = np->next;
  129.                         free((char *)np);
  130.                         return 0;
  131.                 }
  132.         }
  133.  
  134.         return 0;
  135. }
  136.  
  137. static int dokicks(int argc, char *argv[])
  138. {
  139.         struct nntpservers *np;
  140.  
  141.         argc = argc;
  142.  
  143.         for(np = Nntpservers; np != NULLNNTP; np = np->next)
  144.         {
  145.                 if (stricmp(np->name, argv[1]) == 0 ||
  146.                     stricmp(np->abbr, argv[1]) == 0)
  147.                 {
  148.                         /* If the timer is not running, the timeout function has
  149.                          * already been called and we don't want to call it again.
  150.                          */
  151.                         if(run_timer(&np->nntpcli_t))
  152.                         {
  153.                                 np->state = NN_INIT_STATE;
  154.                                 np->stage = NN_INIT_STAGE;
  155.                                 stop_timer(&np->nntpcli_t);
  156.                                 nntptick((void *)np);
  157.                         }
  158.  
  159.                         return 0;
  160.                 }
  161.         }
  162.  
  163.         return 0;
  164. }
  165.  
  166. static int dostop(int argc, char *argv[])
  167. {
  168.         struct nntpservers *np;
  169.  
  170.         argc = argc;
  171.  
  172.         for(np = Nntpservers; np != NULLNNTP; np = np->next)
  173.         {
  174.                 if (stricmp(np->name, argv[1]) == 0 ||
  175.                     stricmp(np->abbr, argv[1]) == 0)
  176.                 {
  177.                         quit(np, FALSE);
  178.                         start_timer(&np->nntpcli_t);
  179.                         return 0;
  180.                 }
  181.         }
  182.  
  183.         return 0;
  184. }
  185.  
  186. static void make_got_table(int at, void *handle)
  187. {
  188.         char buffer[256];
  189.         int loop;
  190.         static long file_len;
  191.         message_data temp;
  192.         struct nntpservers *cb;
  193.  
  194.         at = at;
  195.         cb = (struct nntpservers *) handle;
  196.  
  197.         if (cb->got_table == NULL)
  198.         {
  199.                 cb->msg_tot = 0;
  200.                 if (!flex_alloc((flex_ptr) &(cb->got_table), ID_LEN))
  201.                         return;
  202.         }
  203.  
  204.         if (cb->id_file == NULLFILE)
  205.         {
  206.                 sprintf(buffer, "<ReadBack$Dir>.%sMail", cb->abbr);
  207.                 if ((cb->id_file = fopen(buffer, "r")) != NULLFILE)
  208.                 {
  209.                         fseek(cb->id_file, 0, SEEK_END);
  210.                         file_len = ftell(cb->id_file);
  211.                         fseek(cb->id_file, 9, SEEK_SET);
  212.                 }
  213.                 else
  214.                 {
  215.                         return;
  216.                 }
  217.         }
  218.  
  219.         if (ftell(cb->id_file) < file_len)
  220.         {
  221.                 if (flex_extend((flex_ptr) &(cb->got_table), (cb->msg_tot + 5) * ID_LEN))
  222.                 {
  223.                         for (loop = 0; loop < 5 && ftell(cb->id_file) < file_len; loop++)
  224.                         {
  225.                                 fread(&temp, sizeof(message_data), 1, cb->id_file);
  226.                                 fgets(buffer, 250, cb->id_file);
  227.                                 fgets(buffer, 250, cb->id_file);
  228.                                 strncpy((cb->got_table)[cb->msg_tot], buffer, ID_LEN);
  229.                                 (cb->got_table)[cb->msg_tot][ID_LEN - 1] = '\0';
  230.                                 rip((cb->got_table)[cb->msg_tot]);
  231.                                 fseek(cb->id_file, temp.comp_bytes + 4L, SEEK_CUR);
  232.                                 cb->msg_tot++;
  233.                         }
  234.                 }
  235.         }
  236.         else
  237.         {
  238.                 fclose(cb->id_file);
  239.                 cb->id_file = NULLFILE;
  240.                 return;
  241.         }
  242.  
  243.         alarm_set(alarm_timenow() + 2, make_got_table, (void *)cb);
  244. }
  245.  
  246. void nntptick(void *tp)
  247. {
  248.         struct socket lsocket, fsocket;
  249.         register struct nntpservers *cb;
  250.  
  251.         cb = (struct nntpservers *)tp;
  252.  
  253.         if (cb == NULLNNTP)  return;
  254.  
  255.         if (cb->state != NN_INIT_STATE) return;
  256.  
  257.         /* setup the socket */
  258.         fsocket.address = cb->ipdest;
  259.         fsocket.port    = NNTP_PORT;
  260.  
  261.         lsocket.address = ip_addr;      /* our ip address */
  262.         lsocket.port    = lport++;      /* next unused port */
  263.  
  264.         /* open nntp connection */
  265.         cb->stage = NN_OPEN_STAGE;      /* init stage placeholder */
  266.         cb->state = NN_OPEN_STATE;      /* init state placeholder */
  267.  
  268.         cb->tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,tcp_window,
  269.         (void(*)())nntp_rec,(void(*)())nntp_cts,(void(*)())nntp_state,0,(char *)cb);
  270.  
  271.         cb->tcb->user = (char *)cb;     /* Upward pointer */
  272.  
  273.         start_timer(&cb->nntpcli_t);    /* restart the timer */
  274. }
  275.  
  276. static BOOL have_we(char *line, struct nntpservers *cb)
  277. {
  278.         int loop = 0;
  279.         char buffer[NNTPMAXLEN];
  280.  
  281.         strcpy(buffer, line);
  282.  
  283.         if (cb->msg_tot == 0) return(FALSE);
  284.         rip(buffer);
  285.         buffer[strlen(buffer) - 1] = '\0';
  286.  
  287.         while (loop < cb->msg_tot && strncmp(&buffer[1], (cb->got_table)[loop], ID_LEN) != 0)
  288.                 loop++;
  289.  
  290.         if (loop < cb->msg_tot) return(TRUE);
  291.  
  292.         if (flex_extend((flex_ptr) &(cb->got_table), (cb->msg_tot + 1) * ID_LEN))
  293.         {
  294.                 strncpy((cb->got_table)[cb->msg_tot], buffer, ID_LEN);
  295.                 (cb->got_table)[cb->msg_tot][ID_LEN - 1] = '\0';
  296.                 cb->msg_tot++;
  297.         }
  298.  
  299.         return(FALSE);
  300. }
  301.  
  302. void nntp_transaction(register struct nntpservers *cb)
  303. {
  304.         register char reply;
  305.         int rcode;
  306.         char line[NNTPMAXLEN + 1], buffer[256];
  307.         static char now[10], date[10], hour[10];
  308.         FILE *temp;
  309.  
  310.         /* Another line follows; ignore this one */
  311.         /* if(cb->buf[0] == '0') return; */
  312.  
  313.         reply = cb->buf[0];
  314.         rcode = atoi(cb->buf);
  315.  
  316.         /* if service shuting down */
  317.         if (cb->state == NN_OPEN_STATE && rcode == 400)
  318.         {
  319.                 quit(cb, FALSE);
  320.                 return;
  321.         }
  322.         else if (cb->state == NN_OPEN_STATE && rcode == 411) /* No such group */
  323.         {
  324.                 cb->state = NN_DATA_STATE;
  325.                 cb->buf[0] = '.';
  326.                 cb->buf[1] = '\n';
  327.                 cb->buf[2] = '\0';
  328.                 cb->stage = NN_NEWG_STAGE;
  329.         }
  330.         else if (cb->state == NN_OPEN_STATE && rcode == 430) /* No such Article */
  331.         {
  332.                 cb->state = NN_DATA_STATE;
  333.                 cb->buf[0] = '.';
  334.                 cb->buf[1] = '\n';
  335.                 cb->buf[2] = '\0';
  336.                 cb->stage = NN_NEWN_STAGE;
  337.         }
  338.     
  339.         switch(cb->state)
  340.         {
  341.               case NN_OPEN_STATE:
  342.                       if (reply == '5') quit(cb, FALSE);
  343.                       else if (reply == '2')
  344.                       {
  345.                               switch(cb->stage)
  346.                               {
  347.                                       case NN_OPEN_STAGE:
  348.                                               cb->stage = NN_NEWG_STAGE;
  349.                                               now[0] = 3;
  350.                                               os_word(14, now);
  351.  
  352.                                               sprintf(buffer, "<NETLITE$Dir>.%sLast", cb->abbr);
  353.                                               if ((temp = fopen(buffer, "r")) != NULL)
  354.                                               {
  355.                                                       if (fgets(date, 10, temp) == NULL)
  356.                                                               os_swi4(OS_ConvertDateAndTime, (int) now, (int) date, 10, (int) "%YR%MN01");
  357.                                                       if (fgets(hour, 10, temp) == NULL)
  358.                                                               strcpy(hour, "000001");
  359.                                                       fclose(temp);
  360.                                               }
  361.                                               else
  362.                                               {
  363.                                                       os_swi4(OS_ConvertDateAndTime, (int) now, (int) date, 10, (int) "%YR%MN01");
  364.                                                       strcpy(hour, "000001");
  365.                                               }
  366.                                               rip(date);
  367.                                               rip(hour);
  368.                                               sendit(cb,"NEWGROUPS %s %s\r\n", date, hour);
  369.                                               break;
  370.                                       case NN_NEWG_STAGE:
  371.                                               cb->state = NN_DATA_STATE;
  372.                                               sprintf(buffer, "<Mail$Dir>.Folder.%sNG", cb->abbr);
  373.                                               cb->tfile = fopen(buffer, "a");
  374.                                               break;
  375.                                       case NN_NEWN_STAGE:
  376.                                               cb->state = NN_DATA_STATE;
  377.                                               sprintf(buffer, "<NETLITE$Dir>.%sNew", cb->abbr);
  378.                                               cb->tfile = fopen(buffer, "w");
  379.                                               break;
  380.                                       case NN_GETN_STAGE:
  381.                                               cb->state = NN_DATA_STATE;
  382.                                               cb->stage = NN_NEWN_STAGE;
  383.                                               sprintf(buffer, "<Mail$Dir>.Folder.%sNews", cb->abbr);
  384.                                               cb->tfile = fopen(buffer, "a");
  385.                                               fprintf(cb->tfile, "#! rnews\n");
  386.                                               break;
  387.                               }
  388.                       }
  389.                       break;
  390.  
  391.               case NN_DATA_STATE:
  392.                       tcp_output(cb->tcb);    /* Send ACK; disk I/O is slow */
  393.                       if (cb->buf[0] == '.'  &&
  394.                           cb->buf[1] == '\n' &&
  395.                           cb->buf[2] == '\0')
  396.                       {
  397.                               cb->state = NN_OPEN_STATE;
  398.                               if (cb->tfile != NULLFILE)
  399.                               {
  400.                                       fclose(cb->tfile);
  401.                                       cb->tfile = NULLFILE;
  402.                               }
  403.  
  404.                               if (cb->stage == NN_NEWN_STAGE)
  405.                               {
  406.                                       if (!cb->rfile)
  407.                                       {
  408.                                               sprintf(buffer, "<NETLITE$Dir>.%sNew", cb->abbr);
  409.                                               cb->rfile = fopen(buffer, "r");
  410.                                       }
  411.  
  412.                                       if (cb->rfile)
  413.                                       {
  414.                                               while(fgets(line, NNTPMAXLEN - 1, cb->rfile) != NULL && have_we(line, cb));
  415.  
  416.                                               if (!feof(cb->rfile))
  417.                                               {
  418.                                                       rip(line);
  419.                                                       sendit(cb, "ARTICLE %s\r\n", line);
  420.                                                       cb->stage = NN_GETN_STAGE;
  421.                                               }
  422.                                               else
  423.                                               {
  424.                                                       fclose(cb->rfile);
  425.                                                       cb->rfile = NULLFILE;
  426.                                                       sprintf(buffer, "<NETLITE$Dir>.%sNew", cb->abbr);
  427.                                                       remove(buffer);
  428.                                                       cb->stage = NN_NEWG_STAGE;
  429.                                               }
  430.                                       }
  431.                               }
  432.  
  433.                               if (cb->stage == NN_NEWG_STAGE)
  434.                               {
  435.                                       if (!cb->sfile)
  436.                                       {
  437.                                               sprintf(buffer, "<NETLITE$Dir>.%sGroup", cb->abbr);
  438.                                               cb->sfile = fopen(buffer, "r");
  439.                                       }
  440.  
  441.                                       if (cb->sfile != NULL)
  442.                                       {
  443.                                               if (fgets(line, NNTPMAXLEN - 25, cb->sfile) != NULL)
  444.                                               {
  445.                                                       rip(line);
  446.                                                       sendit(cb,"NEWNEWS %s %s %s\r\n", line, date, hour);
  447.                                                       cb->stage = NN_NEWN_STAGE;
  448.                                               }
  449.                                               else
  450.                                               {
  451.                                                       fclose(cb->sfile);
  452.                                                       cb->sfile = NULLFILE;
  453.  
  454.                                                       sprintf(buffer, "<NETLITE$Dir>.%sLast", cb->abbr);
  455.                                                       if ((temp = fopen(buffer, "w")) != NULL)
  456.                                                       {
  457.                                                               os_swi4(OS_ConvertDateAndTime, (int)now, (int)date, 10, (int)"%YR%MN%DY");
  458.                                                               os_swi4(OS_ConvertDateAndTime, (int)now, (int)hour, 10, (int)"%24%MI%SE");
  459.                                                               fprintf(temp, "%s\n%s\n", date, hour);
  460.                                                               fclose(temp);
  461.                                                       }
  462.                                                       cb->state = NN_QUIT_STATE;
  463.                                                       quit(cb, TRUE);
  464.                                               }
  465.                                       }
  466.                                       else
  467.                                       {
  468.                                               quit(cb, FALSE);
  469.                                       }
  470.                               }
  471.                       }
  472.                       else
  473.                       {
  474.                               /* Append to data file - JSN 28/03/93 */
  475.                               if (strcmp(cb->buf, "..", 2) == 0)
  476.                               {
  477.                                       if (fprintf(cb->tfile, cb->buf + 1) < 0)
  478.                                       {
  479.                                               cb->state = NN_OPEN_STATE;
  480.                                               tprintf(cb->tcb, "File write error\n");
  481.                                       }
  482.                               }
  483.                               else
  484.                               {
  485.                                       if (fprintf(cb->tfile, cb->buf) < 0)
  486.                                       {
  487.                                               cb->state = NN_OPEN_STATE;
  488.                                               tprintf(cb->tcb, "File write error\n");
  489.                                       }
  490.                               }
  491.                       }
  492.                       break;
  493.         }
  494. }
  495.  
  496. /* close down link after a failure */
  497. static void quit(struct nntpservers *cb, BOOL normal)
  498. {
  499.         cb->state = NN_QUIT_STATE;
  500.         sendit(cb, quitcmd);            /* issue a quit command */
  501.         close_tcp(cb->tcb);             /* close up connection */
  502.  
  503.         if (cb->rfile != NULLFILE) fclose(cb->rfile);
  504.         if (cb->sfile != NULLFILE) fclose(cb->sfile);
  505.         if (cb->tfile != NULLFILE) fclose(cb->tfile);
  506.  
  507.         cb->rfile = NULLFILE;
  508.         cb->sfile = NULLFILE;
  509.         cb->tfile = NULLFILE;
  510.  
  511.         start_timer(&cb->nntpcli_t);
  512. }
  513.  
  514. /* nntp receiver upcall routine.  fires up the state machine to parse input */
  515. static void nntp_rec(struct tcb *tcb, int16 cnt)
  516. {
  517.         register struct nntpservers *cb;
  518.         char c;
  519.         struct mbuf *bp;
  520.  
  521.         if ((cb = (struct nntpservers *)tcb->user) == NULL)       /* point to our struct */
  522.         {
  523.                  close_tcp(tcb);
  524.                  return;
  525.         }
  526.  
  527.         recv_tcp(tcb, &bp, cnt);  /* suck up chars from low level routine */
  528.  
  529.         /* Assemble input line in buffer, return if incomplete */
  530.         while (pullup(&bp, &c, 1) == 1)
  531.         {
  532.                 switch (c)
  533.                 {
  534.                       case '\r':      /* strip cr's */
  535.                               continue;
  536.                       case '\n':      /* line is finished, go do it! */
  537.                               cb->buf[cb->cnt++] = '\n';
  538.                               cb->buf[cb->cnt] = '\0';
  539.                               nntp_transaction(cb);
  540.                               cb->cnt = 0;
  541.                               break;
  542.                       default:        /* other chars get added to buffer */
  543.                               cb->buf[cb->cnt++] = c;
  544.                               if (cb->cnt > NNTPMAXLEN - 2)
  545.                               {
  546.                                       cb->buf[cb->cnt] = '\0';
  547.                                       nntp_transaction(cb);
  548.                                       cb->cnt = 0;
  549.                               }
  550.                               break;
  551.                 }
  552.         }
  553. }
  554.  
  555. /* nntp transmitter ready upcall routine.  twiddles cts flag */
  556. static void nntp_cts(struct tcb *tcb, int16 cnt)
  557. {
  558.         register struct nntpservers *cb;
  559.  
  560.         cb = (struct nntpservers *)tcb->user;       /* point to our struct */
  561.  
  562.         /* don't do anything until/unless we're supposed to be sending */
  563.         if(cb->cts == 0) return;
  564. }
  565.  
  566. /* nntp state change upcall routine. */
  567. static void nntp_state(register struct tcb *tcb, char old, char new)
  568. {
  569.         register struct nntpservers *cb;
  570.  
  571.         old = old;
  572.  
  573.         cb = (struct nntpservers *)tcb->user;
  574.  
  575.         switch(new)
  576.         {
  577.               case ESTABLISHED:
  578.                       cb->state = NN_OPEN_STATE;/* shouldn't be needed */
  579.                       break;
  580.               case CLOSE_WAIT:
  581.                       close_tcp(tcb);           /* shut things down */
  582.                       break;
  583.               case CLOSED:
  584.                       /* if this close was not done by us ie. a RST */
  585.                       if(cb->tfile != NULLFILE) fclose(cb->tfile);
  586.                       /* del_session(cb); */
  587.                       del_tcp(tcb);
  588.                       break;
  589.               default:
  590.                       break;
  591.         }
  592. }
  593.  
  594. /* Send message back to server */
  595. static void sendit(struct nntpservers *cb, char *fmt, ...)
  596. {
  597.         va_list argptr;
  598.         struct mbuf *bp;
  599.         char tmpstring[256];
  600.  
  601.         va_start(argptr,fmt);
  602.         vsprintf(tmpstring,fmt,argptr);
  603.         va_end(argptr);
  604.  
  605.         bp = qdata(tmpstring, (int16)strlen(tmpstring));
  606.         send_tcp(cb->tcb, bp);
  607. }
  608.  
  609.